use std::io::{self, Write};
use termion::{raw::{RawTerminal, IntoRawMode}, event::Key, input::TermRead, color};

use crate::editor::Position;

#[derive(Debug)]
pub struct Size {
    pub width: usize,
    pub height: usize,
}

pub struct Terminal {
    size: Size,
    pub _std_out: RawTerminal<io::Stdout>,
}

impl Terminal {
    pub fn default() -> Result<Self, io::Error> {
        let size = termion::terminal_size()?;

        Ok(Self {
            size: Size {
                height: (size.1 as usize).saturating_sub(2),    //leave 2 rows as status/msg bar
                width: size.0 as usize,
            },
            _std_out: io::stdout().into_raw_mode()?,
        })
    }

    pub fn size(&self) -> &Size {
        &self.size
    }

    pub fn clear_screen() {
        print!("{}", termion::clear::All);
    }

    pub fn hide_cursor() {
        print!("{}", termion::cursor::Hide);
    }

    pub fn show_cursor() {
        print!("{}", termion::cursor::Show);
    }

    pub fn cursor_position(position: &Position) {
        let x = position.x.saturating_add(1) as u16;
        let y = position.y.saturating_add(1) as u16;
        print!("{}", termion::cursor::Goto(x, y));
    }

    pub fn clear_current_line() {
        print!("{}", termion::clear::CurrentLine);
    }

    pub fn flush() -> Result<(), io::Error> {
        io::stdout().flush()
    }

    pub fn read_key() -> Result<Key, io::Error> {
        loop {
            if let Some(k) = io::stdin().lock().keys().next() {
                return k;
            }
        }
    }

    pub fn bg_color(color: color::Rgb) {
        print!("{}", color::Bg(color));
    }

    pub fn reset_bg_color() {
        print!("{}", color::Bg(color::Reset));
    }

    pub fn fg_color(color: color::Rgb) {
        print!("{}", color::Fg(color));
    }

    pub fn reset_fg_color() {
        print!("{}", color::Fg(color::Reset));
    }
}
